package com.lqian.demo05;

/**
 * 两个线程交替按顺序输出1-100
 * 第一个线程只能输出偶数，第二线程输出奇数，想象下两个小孩轮流喊数。
 * 两个线程交替输出，这就意味着它俩是需要协同的，协同意味着二者之间要有信息传递，
 * 如何相互传递信息？ 你可能直接想到，既然是0-100的数按顺序交替输出，那么每个进程只需要时不时看看计数器的值，
 * 然后看是否轮到自己输出了就行。没错，这就是解法一的思路。
 *
 * 不仅顺序不对，还有重复和丢失！问题在哪？回到代码中cnt++; System.out.println("thread_" + id + " num:" + cnt);
 * 这两行，它主要包含两个动作，cnt++和输出，当cnt++执行完成后可能就已经触发了另一个线程的输出。
 * 简化下执行流程，每个时刻JVM有4个动作要执行。
 * thread_0 cnt++
 * thread_0 print
 * thread_1 cnt++
 * thread_1 print
 * 根据Java as-if-serial语义，jvm只保证单线程内的有序性，不保证多线程之间的有序性，
 * 所以上面4个步骤的执行次序可能是 1 2 3 4，也可能是1 3 2 4，更可能是1 3 4 2，对于上面的代码而言就是最终次序可能会发生变化。
 * 另外，cnt++ 可以拆解为两行底层指令，tmp = cnt + 1; cnt = tmp，当两个线程同时执行上述指令时就会面临和1 2 3 4步骤同样的问题，……
 * 没错，多线程下的行为，和你女朋友的心思一样难以琢磨。
 * 如何解决这个问题？解决方案本质上都是保证代码执行顺和我们预期的一样就行，正确的解法一和后面几个解法本质上都是同样的原理，只是实现方式不一样。
 *
 * @author：Melody_LQ
 * @time：2022/8/22 7:27 下午
 */
public class AltermatelyOutput1To100 extends Thread{

    private static int count = 1;
    private int id ; //线程编号

    public AltermatelyOutput1To100(int id){
        this.id = id;
    }

    @Override
    public void run() {
        while (count <= 100){
            while (count % 2 == id){
                    count ++;
                System.out.println("thread_"+id+" num--> " + count);
            }
        }
    }

    public static void main(String[] args) {
        new AltermatelyOutput1To100(0).start();
        new AltermatelyOutput1To100(1).start();
    }
}
